<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>JavaScript 闭包示例</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        line-height: 1.6;
        max-width: 800px;
        margin: 0 auto;
        padding: 20px;
        color: #333;
      }
      h1 {
        color: #2c3e50;
        border-bottom: 2px solid #3498db;
        padding-bottom: 10px;
      }
      .example {
        background-color: #f9f9f9;
        border-left: 4px solid #3498db;
        padding: 15px;
        margin: 20px 0;
      }
      button {
        background-color: #3498db;
        color: white;
        border: none;
        padding: 8px 16px;
        margin: 5px;
        border-radius: 4px;
        cursor: pointer;
      }
      button:hover {
        background-color: #2980b9;
      }
      pre {
        background-color: #f0f0f0;
        padding: 10px;
        border-radius: 4px;
        overflow-x: auto;
      }
    </style>
  </head>
  <body>
    <h1>JavaScript 闭包示例</h1>

    <p>闭包是指有权访问另一个函数作用域中的变量的函数。简单来说，当一个内部函数可以访问其外部函数的变量时，就形成了闭包。</p>

    <div class="example">
      <h2>示例1: 基本闭包</h2>
      <p>这个例子展示了一个简单的闭包，内部函数可以访问外部函数的变量。</p>
      <button onclick="example1()">运行示例1</button>
      <pre><code>
function outer() {
    let outerVar = "我在外部函数中";
    
    function inner() {
        console.log(outerVar); // 访问外部函数的变量
    }
    
    return inner;
}

const closure = outer();
closure(); // 输出: "我在外部函数中"
        </code></pre>
    </div>

    <div class="example">
      <h2>示例2: 计数器闭包</h2>
      <p>这个例子展示了如何使用闭包创建私有变量和计数器。</p>
      <button onclick="example2()">运行示例2</button>
      <div id="counterOutput"></div>
      <pre><code>
function createCounter() {
    let count = 0;
    
    return {
        increment: function() {
            count++;
            return count;
        },
        decrement: function() {
            count--;
            return count;
        },
        getCount: function() {
            return count;
        }
    };
}

const counter = createCounter();
        </code></pre>
    </div>

    <div class="example">
      <h2>示例3: 闭包在循环中的应用</h2>
      <p>这个例子展示了闭包如何解决循环中的变量作用域问题。</p>
      <button onclick="example3()">运行示例3</button>
      <div id="loopOutput"></div>
      <pre><code>
// 不使用闭包时的问题
for (var i = 1; i <= 3; i++) {
    setTimeout(function() {
        console.log(i); // 总是输出4
    }, 1000);
}

// 使用闭包解决
for (var i = 1; i <= 3; i++) {
    (function(j) {
        setTimeout(function() {
            console.log(j); // 正确输出1,2,3
        }, 1000);
    })(i);
}
        </code></pre>
    </div>

    <div class="example">
      <h2>示例4: 闭包实现数据私有化</h2>
      <p>这个例子展示了如何使用闭包创建私有变量和方法。</p>
      <button onclick="example4()">运行示例4</button>
      <div id="privateOutput"></div>
      <pre><code>
function createPerson(name) {
    let age = 0; // 私有变量
    
    return {
        getName: function() {
            return name;
        },
        getAge: function() {
            return age;
        },
        celebrateBirthday: function() {
            age++;
            return `${name}现在${age}岁了!`;
        }
    };
}

const person = createPerson("张三");
        </code></pre>
    </div>

    <script>
      // 示例1的实现
      function example1() {
        function outer() {
          let outerVar = "我在外部函数中";

          function inner() {
            outerVar = "我在外部函数中inner";
            console.log(outerVar); // 访问外部函数的变量
            alert(outerVar);
          }
          console.log(outerVar, "out"); // 访问外部函数的变量

          return inner;
        }

        const closure = outer();
        closure(); // 输出: "我在外部函数中"
      }

      // 示例2的实现
      function example2() {
        function createCounter() {
          let count = 0;

          return {
            increment: function () {
              count++;
              return count;
            },
            decrement: function () {
              count--;
              return count;
            },
            getCount: function () {
              return count;
            },
          };
        }

        const counter = createCounter();

        let output = "当前计数: " + counter.getCount() + "<br>";
        output += "增加后: " + counter.increment() + "<br>";
        output += "增加后: " + counter.increment() + "<br>";
        output += "减少后: " + counter.decrement() + "<br>";
        output += "最终计数: " + counter.getCount();

        document.getElementById("counterOutput").innerHTML = output;
      }

      // 示例3的实现
      function example3() {
        let output = "<h3>不使用闭包:</h3>";

        // 不使用闭包时的问题
        for (var i = 1; i <= 3; i++) {
          setTimeout(function () {
            console.log(i); // 总是输出4
          }, 1000);
        }
        output += "查看控制台，所有输出都是4<br>";

        output += "<h3>使用闭包:</h3>";

        // 使用闭包解决
        for (var i = 1; i <= 3; i++) {
          (function (j) {
            setTimeout(function () {
              console.log(j); // 正确输出1,2,3
              document.getElementById("loopOutput").innerHTML += j + "<br>";
            }, 1000 * i);
          })(i);
        }

        document.getElementById("loopOutput").innerHTML = output;
      }

      // 示例4的实现
      function example4() {
        function createPerson(name) {
          let age = 0; // 私有变量

          return {
            getName: function () {
              return name;
            },
            getAge: function () {
              return age;
            },
            celebrateBirthday: function () {
              age++;
              return `${name}现在${age}岁了!`;
            },
          };
        }

        const person = createPerson("张三");

        let output = `姓名: ${person.getName()}<br>`;
        output += `初始年龄: ${person.getAge()}<br>`;
        output += `过生日: ${person.celebrateBirthday()}<br>`;
        output += `过生日: ${person.celebrateBirthday()}<br>`;
        output += `当前年龄: ${person.getAge()}`;

        document.getElementById("privateOutput").innerHTML = output;
      }
    </script>
  </body>
</html>
